import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Robot;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import javax.media.j3d.*;

/**
 * control the viewer using the mouse, as implemented in many First Person Shoot style games.
 * Modified from the original source which may be found at http://www.uni-koblenz.de/~tkranz/MouseFreeLookBehavior.java
 * (retrieved Tuesday 15/5/2007)
 * 
 * @author Thomas
 * @contribted Andrew Cunningham
 */
public class MouseLookBehavior extends Behavior {
	
	//the distance variables 
	float movementX = 0.0f;
	float movementY = 0.0f;	
	
	//some nescessary objects
	private Point center;
	private Robot robot;
	private WakeupOnAWTEvent event;
	private AWTEvent [] eventqueue; 
	private WakeupOr wca;
	
	//nescessary transforms and a group
	private Transform3D t3d     = new Transform3D();
	private Transform3D tempInv = new Transform3D();
	private Transform3D temp    = new Transform3D();
	private Transform3D temp2   = new Transform3D();
	private TransformGroup tg;
	
	Component component;
	
	//one constructor
	public MouseLookBehavior(Component component, TransformGroup tg){
		
		this.component = component;
		this.tg = tg;
		center = new Point(Toolkit.getDefaultToolkit().getScreenSize().width / 2,Toolkit.getDefaultToolkit().getScreenSize().height / 2);
		 
		
		try{
			robot = new Robot();
			robot.mouseMove((int)center.x , (int)center.y); //re-center the pointer
		} catch(Exception exc) {
			System.out.println("java.awt.Robot is not supported!");
		}
		getCentre();
		wca = new WakeupOr(new WakeupCriterion[]{
				new WakeupOnAWTEvent(MouseEvent.MOUSE_DRAGGED), 
				new WakeupOnAWTEvent(MouseEvent.MOUSE_MOVED)});
	}
	
	//init behavior
	public void initialize() {
		
		wakeupOn(wca);
		
	}

	public int getOffset(int width, int centre, int position){
		if (position < centre - (width / 2))
			return position - (centre - (width / 2));
		if (position > centre + (width / 2))
			return position - (centre + (width / 2));
		return 0;
	}
	
	//get it going...
	public void processStimulus(Enumeration events) {
		
		getCentre();
		event = (WakeupOnAWTEvent)events.nextElement(); //convert the one element in the enum
		eventqueue = event.getAWTEvent(); //retrieve the events array
		MouseEvent mouse = (MouseEvent)eventqueue[0]; //convert the one event to a MouseEvent
		
		//x-distance and y-distance of the pointer from center in this event
		movementX = getOffset(10, (int)getCentre().x, mouse.getX());//mouse.getX() - (int)getCentre().x;   
		movementY = getOffset(10, (int)getCentre().y, mouse.getY());//mouse.getY() - (int)getCentre().y;
		//System.out.println(mouse);
		
		//System.out.println(center);
		if (movementX != 0 || movementY != 0)
			robot.mouseMove((int)(mouse.getX() - movementX), (int)(mouse.getY() - movementY)); //re-center the pointer		
		
		//retrieve Transform3D and multiply with inverse X-rotation transform
		tg.getTransform(t3d);		
		t3d.mul(tempInv);
		
		//rotation about Y-axis
		temp.rotY(Math.toRadians(-movementX * 0.3));
		t3d.mul(temp);
		
		//rotation about X-axis
		temp.rotX(Math.toRadians(-movementY * 0.3));		
		temp2.mul(temp);
		t3d.mul(temp2);
		
		//save X-rotation and invert the temp. transform
		tempInv.set(temp2);
		tempInv.invert();
		
		tg.setTransform(t3d); //set the transform
			
		wakeupOn(wca); //re-initialize wake-up criterion
		
	}
	
	protected Point getCentre(){
		
		center.x = component.getLocationOnScreen().x + component.getWidth() / 2;
		center.y = component.getLocationOnScreen().y + component.getHeight() / 2;
		return center;
	}

}